
<!DOCTYPE html>
<!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]-->
<!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]-->
<!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class="no-js" lang="en"><!--<![endif]-->
<head>
  <meta charset="utf-8">
  <title>MCS Lock - Yebangyu's Blog</title>
  <meta name="author" content="Yebangyu">

  
  <meta name="description" content="本文介绍了如何用MCS Lock和MCS算法来实现高效的spin lock">
  <meta name="keywords" content="spin lock mcs lock peterson">

  <!-- http://t.co/dKP3o1e -->
  <meta name="HandheldFriendly" content="True">
  <meta name="MobileOptimized" content="320">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  
  <link rel="canonical" href="http://www.yebangyu.org/blog/2016/08/21/mcslock/">
  <link href="/favicon.png" rel="icon">
  <link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
  <link href="/atom.xml" rel="alternate" title="Yebangyu's Blog" type="application/atom+xml">
  <script src="/javascripts/modernizr-2.0.js"></script>
  <script src="//ajax.lug.ustc.edu.cn/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  <script>!window.jQuery && document.write(unescape('%3Cscript src="/javascripts/libs/jquery.min.js"%3E%3C/script%3E'))</script>
  <script src="/javascripts/octopress.js" type="text/javascript"></script>
  <!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="//fonts.lug.ustc.edu.cn/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="//fonts.lug.ustc.edu.cn/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<!-- mathjax config similar to math.stackexchange -->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  jax: ["input/TeX", "output/HTML-CSS"],
  tex2jax: {
    inlineMath: [ ['$', '$'] ],
    displayMath: [ ['$$', '$$']],
    processEscapes: true,
    skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
  },
  messageStyle: "none",
  "HTML-CSS": { preferredFont: "TeX", availableFonts: ["STIX","TeX"] }
});
</script>
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" type="text/javascript"></script>

  

</head>

<body   >
  <header role="banner"><hgroup>
  <h1><a href="/">Yebangyu's Blog</a></h1>
  
    <h2>Fond of Concurrency Programming and Machine Learning</h2>
  
</hgroup>

</header>
  <nav role="navigation"><ul class="subscription" data-subscription="rss">
  <li><a href="/atom.xml" rel="subscribe-rss" title="subscribe via RSS">RSS</a></li>
  
</ul>
  
<form action="https://www.google.com/search" method="get">
  <fieldset role="search">
    <input type="hidden" name="sitesearch" value="www.yebangyu.org">
    <input class="search" type="text" name="q" results="0" placeholder="Search"/>
  </fieldset>
</form>
  
<ul class="main-navigation">
  <li><a href="/">Blog</a></li>
  <li><a href="/blog/archives">Archives</a></li>
  <li><a href="/about">About Me</a></li>
</ul>

</nav>
  <div id="main">
    <div id="content">
      <div>
<article class="hentry" role="article">
  
  <header>
    
      <h1 class="entry-title">MCS Lock</h1>
    
    
      <p class="meta">
        




<time class='entry-date' datetime='2016-08-21T20:25:11+08:00'><span class='date'><span class='date-month'>Aug</span> <span class='date-day'>21</span><span class='date-suffix'>st</span>, <span class='date-year'>2016</span></span> <span class='time'>8:25 pm</span></time>
        
      </p>
    
  </header>


<div class="entry-content"><h2 id="section">回顾</h2>

<p><a href="http://www.yebangyu.org/blog/2016/05/26/ticketlock/">上回</a> 我们介绍了Ticket Lock算法，和传统的简单的CAS操作来实现spin lock相比，它提供了不少很好的性质：比如FIFO、没有饥饿等等。</p>

<p>但是根据<a href="https://pdos.csail.mit.edu/papers/linux:lock.pdf">论文</a>，ticket lock的scalability很差。我们不妨简单回顾一下（代码片段也摘自该论文）：</p>

<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
<span class="line-number">9</span>
<span class="line-number">10</span>
<span class="line-number">11</span>
<span class="line-number">12</span>
<span class="line-number">13</span>
<span class="line-number">14</span>
<span class="line-number">15</span>
</pre></td><td class="code"><pre><code class="c++"><span class="line"><span class="k">struct</span> <span class="kt">spinlock_t</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="kt">int</span> <span class="n">current_ticket</span> <span class="p">;</span>
</span><span class="line">  <span class="kt">int</span> <span class="n">next_ticket</span> <span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line"><span class="kt">void</span> <span class="n">spin_lock</span> <span class="p">(</span><span class="kt">spinlock_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="n">atomic_fetch_and_inc</span><span class="p">(</span><span class="o">&amp;</span><span class="n">lock</span> <span class="o">-&gt;</span> <span class="n">next_ticket</span> <span class="p">);</span>
</span><span class="line">  <span class="k">while</span> <span class="p">(</span><span class="n">t</span> <span class="o">!=</span> <span class="n">lock</span><span class="o">-&gt;</span><span class="n">current_ticket</span> <span class="p">)</span>
</span><span class="line">  <span class="p">;</span> <span class="cm">/* spin */</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line"><span class="kt">void</span> <span class="n">spin_unlock</span> <span class="p">(</span><span class="kt">spinlock_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="n">lock</span><span class="o">-&gt;</span><span class="n">current_ticket</span><span class="o">++</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>

<!--more-->

<p>正如论文中指出的那样，当某个core上持有锁的线程释放锁时，它将把其他core上的<code>current_ticket</code>对应的cacheline都invalid掉，之前所有等锁的线程都会通过bus来读取最新的cacheline，这将造成“拥堵”(也就是所谓的bus traffic)。由于在绝大多数体系结构下，这些读取请求都会被串行化，one by one的处理，因此<code>spin_lock</code>所需时间将正比于等待锁的线程数目。</p>

<p>本质上，这里的问题还是在于资源共享：所有等锁线程都spin在同一个全局变量上。如果每个线程仅仅spin在本地变量(该线程私有的变量)，那么将有效的提高scalability。本文要介绍的MCS Lock就是这样的思路。</p>

<h2 id="section-1">实现</h2>

<p>这次，我们先给出实现（环境为：GCC 4.8 + X86体系结构 + Ubuntu 14.04 32bit系统），然后再讲解算法。</p>

<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
<span class="line-number">9</span>
<span class="line-number">10</span>
<span class="line-number">11</span>
<span class="line-number">12</span>
<span class="line-number">13</span>
<span class="line-number">14</span>
<span class="line-number">15</span>
<span class="line-number">16</span>
<span class="line-number">17</span>
<span class="line-number">18</span>
<span class="line-number">19</span>
<span class="line-number">20</span>
<span class="line-number">21</span>
<span class="line-number">22</span>
<span class="line-number">23</span>
<span class="line-number">24</span>
<span class="line-number">25</span>
<span class="line-number">26</span>
<span class="line-number">27</span>
<span class="line-number">28</span>
<span class="line-number">29</span>
<span class="line-number">30</span>
<span class="line-number">31</span>
<span class="line-number">32</span>
<span class="line-number">33</span>
<span class="line-number">34</span>
<span class="line-number">35</span>
<span class="line-number">36</span>
<span class="line-number">37</span>
<span class="line-number">38</span>
<span class="line-number">39</span>
<span class="line-number">40</span>
<span class="line-number">41</span>
<span class="line-number">42</span>
<span class="line-number">43</span>
<span class="line-number">44</span>
<span class="line-number">45</span>
<span class="line-number">46</span>
<span class="line-number">47</span>
<span class="line-number">48</span>
<span class="line-number">49</span>
<span class="line-number">50</span>
<span class="line-number">51</span>
<span class="line-number">52</span>
<span class="line-number">53</span>
<span class="line-number">54</span>
<span class="line-number">55</span>
</pre></td><td class="code"><pre><code class="c++"><span class="line"><span class="cp">#define COMPILER_BARRIER() __asm__ __volatile__(&quot;&quot; : : : &quot;memory&quot;)</span>
</span><span class="line"><span class="cp">#define CPU_RELAX() __asm__ __volatile__(&quot;pause\n&quot;: : :&quot;memory&quot;)</span>
</span><span class="line"><span class="cp">#define CAS(address, exp, target) __sync_bool_compare_and_swap(address, exp, target)</span>
</span><span class="line"><span class="cp">#define ATOMIC_EXCHANGE(address, val) __atomic_exchange_n(address, val, __ATOMIC_SEQ_CST)</span>
</span><span class="line"><span class="cp">#define CPU_BARRIER() __sync_synchronize()</span>
</span><span class="line"><span class="c1">//=========================================</span>
</span><span class="line">
</span><span class="line"><span class="k">struct</span> <span class="n">mcs_lock_node</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="k">volatile</span> <span class="kt">int</span> <span class="n">waiting</span><span class="p">;</span>
</span><span class="line">  <span class="n">mcs_lock_node</span> <span class="o">*</span><span class="k">volatile</span> <span class="n">next</span><span class="p">;</span>
</span><span class="line"><span class="p">};</span>
</span><span class="line">
</span><span class="line"><span class="k">typedef</span> <span class="n">mcs_lock_node</span> <span class="o">*</span><span class="k">volatile</span> <span class="n">mcs_lock</span><span class="p">;</span>
</span><span class="line">
</span><span class="line"><span class="k">static</span> <span class="n">mcs_lock_node</span><span class="o">*</span> <span class="nf">get_my_mcs_node</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="k">static</span> <span class="n">__thread</span> <span class="n">mcs_lock_node</span> <span class="n">my_mcs_node</span><span class="p">;</span>
</span><span class="line">  <span class="k">return</span> <span class="o">&amp;</span><span class="n">my_mcs_node</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line">
</span><span class="line"><span class="k">static</span> <span class="kt">void</span> <span class="nf">spin_lock</span><span class="p">(</span><span class="n">mcs_lock</span> <span class="o">&amp;</span><span class="n">lock</span><span class="p">)</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="n">mcs_lock_node</span> <span class="o">*</span><span class="n">me</span> <span class="o">=</span> <span class="n">get_my_mcs_node</span><span class="p">();</span>
</span><span class="line">  <span class="n">mcs_lock_node</span> <span class="o">*</span><span class="n">tmp</span> <span class="o">=</span> <span class="n">me</span><span class="p">;</span>
</span><span class="line">  <span class="n">mcs_lock_node</span> <span class="o">*</span><span class="n">pre</span><span class="p">;</span>
</span><span class="line">  <span class="n">me</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class="line">  <span class="n">pre</span> <span class="o">=</span> <span class="n">ATOMIC_EXCHANGE</span><span class="p">(</span><span class="o">&amp;</span><span class="n">lock</span><span class="p">,</span> <span class="n">tmp</span><span class="p">);</span>
</span><span class="line">  <span class="k">if</span> <span class="p">(</span><span class="n">pre</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">    <span class="k">return</span><span class="p">;</span>	
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="n">me</span><span class="o">-&gt;</span><span class="n">waiting</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span><span class="line">  <span class="n">COMPILER_BARRIER</span><span class="p">();</span>
</span><span class="line">  <span class="n">pre</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">me</span><span class="p">;</span>
</span><span class="line">  <span class="k">while</span> <span class="p">(</span><span class="n">me</span><span class="o">-&gt;</span><span class="n">waiting</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">    <span class="n">CPU_RELAX</span><span class="p">();</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="n">CPU_BARRIER</span><span class="p">();</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line">
</span><span class="line"><span class="k">static</span> <span class="kt">void</span> <span class="nf">spin_unlock</span><span class="p">(</span><span class="n">mcs_lock</span> <span class="o">&amp;</span><span class="n">lock</span><span class="p">)</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="n">CPU_BARRIER</span><span class="p">();</span>
</span><span class="line">  <span class="n">mcs_lock_node</span> <span class="o">*</span><span class="n">me</span> <span class="o">=</span> <span class="n">get_my_mcs_node</span><span class="p">();</span>
</span><span class="line">  <span class="n">mcs_lock_node</span> <span class="o">*</span><span class="n">tmp</span> <span class="o">=</span> <span class="n">me</span><span class="p">;</span>
</span><span class="line">  <span class="k">if</span> <span class="p">(</span><span class="n">me</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">    <span class="k">if</span> <span class="p">(</span><span class="n">CAS</span><span class="p">(</span><span class="o">&amp;</span><span class="n">lock</span><span class="p">,</span> <span class="n">tmp</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">))</span> <span class="p">{</span>
</span><span class="line">      <span class="k">return</span><span class="p">;</span>
</span><span class="line">    <span class="p">}</span>
</span><span class="line">    <span class="k">while</span> <span class="p">(</span><span class="n">me</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">      <span class="n">CPU_RELAX</span><span class="p">();</span>
</span><span class="line">    <span class="p">}</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="n">me</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">waiting</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>

<h2 id="section-2">算法</h2>

<p>MCS Lock算法维护一个队列(队尾指针tail)。</p>

<p>lock：尝试加锁的线程首先获得自己的节点，接着通过原子操作<code>ATOMIC_EXCHANGE</code>，将自己插入队列中，并获得插入前队尾指针tail。如果tail指针为空，说明当前锁是空闲的，没有被任何线程占用，因此获得锁成功；如果tail指针不空，那么设置自己的前驱，然后自旋，等待它的前驱(线程)将自己的<code>waiting</code>域置为0。<code>waiting</code>域一旦为0，那么线程结束spin，该线程就变成锁的持有者了。</p>

<p>unlock：释放锁的线程需要检查是否存在后继，如果存在后继，那么将它的后继的<code>waiting</code>域设置为0即可，后继将结束spin，成功获得锁。一切搞定，如54行代码所示。</p>

<p>如果不存在后继，那么这里需要特别特别注意。不存在后继有两种可能：</p>

<p>它是最后一个线程。47-49行处理的就是这种情况。那么这时候只需要把队列置为空即可。</p>

<p>它不是最后一个线程。那么此时存在另外一个线程在进行加锁操作，尝试加锁的线程已经通过28-33行设置了新的队尾指针，但是还没设置它的前驱，也就是还没执行到34行。因此释放锁的线程需要等待，等待34行被其他线程执行，等待它被人设置为别人的前驱。这也就是50-52行所做的事。</p>

<p>简单说来，MCS Lock就是将线程们用队列管理起来；加锁的线程spin在自己的变量上；释放锁的线程只更新它后继的变量。</p>

<h2 id="section-3">练习</h2>

<p>1，MCS Lock的优点是显而易见的，因为每个等待锁的线程都spin在自己的局部的变量上。以至于新版的linux内核已经开始采用它，来代替之前的ticket lock实现。那么，它的缺点呢？</p>

<p>2，列出表格，从公平性、是否出现饥饿、时间空间复杂度等方面，全面对比ticket lock、mcs lock、peterson lock等。</p>

<p>3，编写程序测试这几个算法的性能，考察它们的scalability。</p>

<h2 id="section-4">附录</h2>

<p>MCS Lock测试程序Demo</p>

<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
<span class="line-number">9</span>
<span class="line-number">10</span>
<span class="line-number">11</span>
<span class="line-number">12</span>
<span class="line-number">13</span>
<span class="line-number">14</span>
<span class="line-number">15</span>
<span class="line-number">16</span>
<span class="line-number">17</span>
<span class="line-number">18</span>
<span class="line-number">19</span>
<span class="line-number">20</span>
</pre></td><td class="code"><pre><code class="c++"><span class="line"><span class="cp">#include&lt;pthread.h&gt;</span>
</span><span class="line"><span class="n">mcs_lock</span> <span class="n">global_lock</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class="line"><span class="kt">void</span><span class="o">*</span> <span class="nf">f</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">)</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">1000000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">    <span class="n">spin_lock</span><span class="p">(</span><span class="n">global_lock</span><span class="p">);</span>
</span><span class="line">    <span class="n">spin_unlock</span><span class="p">(</span><span class="n">global_lock</span><span class="p">);</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="kt">pthread_t</span> <span class="n">pthread1</span><span class="p">;</span>
</span><span class="line">  <span class="kt">pthread_t</span> <span class="n">pthread2</span><span class="p">;</span>
</span><span class="line">  <span class="n">pthread_create</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pthread1</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span><span class="line">  <span class="n">pthread_create</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pthread2</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span><span class="line">  <span class="n">pthread_join</span><span class="p">(</span><span class="n">pthread1</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span><span class="line">  <span class="n">pthread_join</span><span class="p">(</span><span class="n">pthread2</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span><span class="line">  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>

</div>


  <footer>
    <p class="meta">
      
  

<span class="byline author vcard">Posted by <span class="fn">Yebangyu</span></span>

      




<time class='entry-date' datetime='2016-08-21T20:25:11+08:00'><span class='date'><span class='date-month'>Aug</span> <span class='date-day'>21</span><span class='date-suffix'>st</span>, <span class='date-year'>2016</span></span> <span class='time'>8:25 pm</span></time>
      

<span class="categories">
  
    <a class='category' href='/blog/categories/bing-xing-bian-cheng/'>并行编程</a>
  
</span>


    </p>
    
      <div class="sharing">
  
  
  
</div>

    
    <p class="meta">
      
        <a class="basic-alignment left" href="/blog/2016/07/12/reentrantlock/" title="Previous Post: 实现可重入锁">&laquo; 实现可重入锁</a>
      
      
        <a class="basic-alignment right" href="/blog/2016/09/09/epochbasedreclamation/" title="Next Post: Lock Free中的Epoch Based Reclamation">Lock Free中的Epoch Based Reclamation &raquo;</a>
      
    </p>
  </footer>
</article>


</div>

<aside class="sidebar">
  
    <section>
  <h1>Recent Posts</h1>
  <ul id="recent_posts">
    
      <li class="post">
        <a href="/blog/2017/03/11/2017/">2017技术成长之路</a>
      </li>
    
      <li class="post">
        <a href="/blog/2017/02/17/virtualfunctionandvariadicparametertemplate/">虚函数和变长参数模板的妙用</a>
      </li>
    
      <li class="post">
        <a href="/blog/2016/12/25/singleton/">Singleton与多线程</a>
      </li>
    
      <li class="post">
        <a href="/blog/2016/12/04/introductiontohazardpointer/">Lock Free中的Hazard Pointer(下)</a>
      </li>
    
      <li class="post">
        <a href="/blog/2016/12/03/gccandperfopt/">性能优化的那些传说和迷思</a>
      </li>
    
  </ul>
</section>
<section>
  <h1>Friends' Link</h1>
  <ul>
    <li>
	  <li><a href="http://www.chongh.wiki/">Diting0x</a></li>
	  <li><a href="http://www.xiaolili.net/">wangli</a></li>
	  <li><a href="http://www.skykewei.top">dukewei</a></li>
	  <li><a href="http://irwenqiang.github.io">chenwenqiang</a></li>
      <li><a href="http://www.armsword.com">duruofei</a></li>
    </li>
  </ul>
</section><section>
  <h1>Yebangyu</h1>
  <p>福建人。热爱历史、K歌、NBA</p>
  <p>帝都码农</p>
  <p>历史学家，专治秦汉史</p>
</section>
<section>
 <h1>Categories</h1>
 <ul id="categories">
  <li class='category'><a href='/blog/categories/c-plus-plus/'>c++ (11)</a></li>
<li class='category'><a href='/blog/categories/soupen/'>soupen (4)</a></li>
<li class='category'><a href='/blog/categories/web/'>web (1)</a></li>
<li class='category'><a href='/blog/categories/qi-ta/'>其他 (5)</a></li>
<li class='category'><a href='/blog/categories/li-shi/'>历史 (2)</a></li>
<li class='category'><a href='/blog/categories/bing-xing-bian-cheng/'>并行编程 (20)</a></li>
<li class='category'><a href='/blog/categories/xing-neng-you-hua/'>性能优化 (2)</a></li>
<li class='category'><a href='/blog/categories/suan-fa/'>算法 (4)</a></li>
<li class='category'><a href='/blog/categories/bian-yi-lian-jie/'>编译链接 (2)</a></li>

 </ul>
</section>




  
</aside>


    </div>
  </div>
  <footer role="contentinfo"><!-- mathjax config similar to math.stackexchange -->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  jax: ["input/TeX", "output/HTML-CSS"],
  tex2jax: {
    inlineMath: [ ['$', '$'] ],
    displayMath: [ ['$$', '$$']],
    processEscapes: true,
    skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
  },
  messageStyle: "none",
  "HTML-CSS": { preferredFont: "TeX", availableFonts: ["STIX","TeX"] }
});
</script>
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" type="text/javascript"></script>
<p>
  Copyright &copy; 2017 - Yebangyu -
  <span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
<script type="text/javascript">var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");document.write(unescape("%3Cspan id='cnzz_stat_icon_1257548193'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s11.cnzz.com/z_stat.php%3Fid%3D1257548193' type='text/javascript'%3E%3C/script%3E"));</script>

</footer>
  











</body>
</html>
